/** @file
 *  @brief AEye LiDAR Sensor API.
 *  Copyright (c) 2017-2019, AEye
 *  All rights reserved.
 */

#ifndef AEYE_AEYEAPI_H
#define AEYE_AEYEAPI_H

#include <cstdint>
#include <unordered_map>

#include "AEyeSDKStructures.hpp"
#include "AEyeSDKStructuresDev.hpp"
#include "PacketVersions.hpp"
#include "DiagnosticAPI.hpp"

/// @namespace AEye Sensor API
namespace aeye {

enum AEyeCommands : uint16_t {
  //  0x00--0x04 = General Status
  CMD_GET_BUILD_INFO                  = 0x01, //!< Returns the GIT hash that represents the current build
  CMD_GET_HW_MODEL                    = 0x04, //!< Returns the sensor ModelType (ProductID, Variation & Version)

  //  0x05--0x0f = Set configuration commands
  CMD_SET_NETWORK_CONFIG              = 0x05, //!< Set system ip, client ip, ports
  CMD_SET_TIME                        = 0x06, //!< Sets the system time to the given timeval and timezone
  CMD_SET_NTP_SERVER                  = 0x08, //!< Sets the system NTPD to run based off the given server IP address
  CMD_GET_NTP_STATUS                  = 0x09, //!< Retrieves system NTPD parameters
  CMD_SET_PTP_SERVER                  = 0x02, //!< Sets the system PTPD to run based off the given server IP address
  CMD_GET_PTP_STATUS                  = 0x07, //!< Retrieves system PTPD parameters
  CMD_SET_GPTP_SERVER                 = 0xFA, //!< Sets the system gPTP to run based off the given configuration file
  CMD_GET_GPTP_STATUS                 = 0xFB, //!< Retrieves system gPTP parameters
  CMD_SET_LASER_ENABLE                = 0xFE, //!< Enable/disable the laser pump AND set its power based
  CMD_SET_RANGE_GATE_DELAY            = 0x0B, //!< Specify Range Gate Delay in meters
  CMD_SET_POSE                        = 0x0C, //!< Specify sensor pose (x, y, z, yaw, pitch, roll)
  CMD_SET_ERPS_BOX_IN_CAM_COORDS      = 0x0F, //!< Specify bounding box for high-energy pulses.

  //  0x10--0x14 = general control commands
  CMD_START                           = 0x10, //!< Start the system, expect RET_RANGES
  CMD_STOP                            = 0x11, //!< Stop the system
  CMD_TOGGLE_HAWKEYE                  = 0x13, //!< Stop or start the HawkEye
  CMD_KILL_SERVICE                    = 0x14,

  // Alternative to 0x0A
  CMD_SET_LASER_CONFIG_FLOAT          = 0x1A, //!< Specify laser scan parameters as float


  //  0x15--0x2f = Mode selection
  CMD_SET_PASSIVE_SENSING_MODE        = 0x1C, //!< Request to select a passive sensing mode.
  CMD_SET_HAWKEYE_POINT_MODE          = 0x1D,  //!< Request to select the HawkEye debug point mode.
  CMD_RET_MARKER_POINTS               = 0x1E, //!< Request the service to return "good" marker points along with intended points
  CMD_SET_ADVANCED_RX_SWEEP           = 0x20, //!< Request to perform the ARx Sweep Function
  CMD_SET_ADVANCED_RX_STATIC_MODE     = 0x21, //!< Request to perform the ARx Static Mode
  CMD_GENERATE_ARX_LUT_V2             = 0x23, //!< Generate ARx LUT (V2: intensity via RxFifo returns)
  CMD_SET_MODE_MULTI_ECHOES           = 0x24,
  CMD_GET_GENERATE_ARX_LUT_V2_STATUS  = 0x25, //!< Request to read sensor arx lut running state

  //  0x25--0x3f = Configuration commands
  CMD_SET_POINT_RETURN_MASK           = 0x31, //!< Request which point mode to use type packets
  CMD_SET_INTENSITY_TYPE              = 0x32, //!< Request which intensity return type for packets
  //  0x40--0x4f = Internal commands
  CMD_SET_RECEIVER_REGISTER           = 0x42, //!< Request to update receiver register values
  CMD_GET_RECEIVER_REGISTER           = 0x46, //!< Read specific receiver register
  CMD_SET_PASSIVE_MODE_PARAMETER      = 0x47, //!< Change a fill pattern parameter
  CMD_GET_POSE                        = 0x48, //!< Request to read sensor pose (x, y, z, yaw, pitch, roll)
  CMD_GET_ACTIVE_SENSING_STATE        = 0x49, //!< Request to read sensor active sensing subsystem state
  CMD_GET_PASSIVE_SENSING_STATE       = 0x4A, //!< Request to read sensor passive sensing subsystem state
  CMD_GET_ERPS_SENSING_STATE          = 0x4B, //!< Request to read sensor ERPs sensing subsystem state
  CMD_GET_RANGING_STATE               = 0x4D, //!< Request to read sensor range delay
  CMD_GET_LASER_STATE                 = 0x4E, //!< Request to read sensor laser state
  CMD_GET_MARKER_STATE                = 0x4F, //!< Request to read sensor marker point sending state
  // Ids 0x50--0x5f = formatted data output from device
  RET_POINT_CLOUD                     = 0x55, //!< List of points/range returns and associated data
  RET_ADC_BUFFER                      = 0x56, //!< Raw signal buffer
  RET_POINT_CLOUD_DELIM               = 0x57,

  // Ids 0x60--0x6f = Tcp returns
  RET_DEFAULT                         = 0x60, //!< Default return
  RET_UNKNOWN                         = 0xff, //!< Unknown return
  RET_BUILD_INFO                      = 0x61, //!< Server info return
  RET_HW_MODEL                        = 0x62, //!< HW Model type return
  RET_GET_NUM_MULTI_ECHOES            = 0x67,
  RET_GET_MODE_MULTI_ECHOES           = 0x68,

  // Ids 0x70--0x7f = Tcp returns for internal commands
  RET_SCANNER_REGISTER_VALUE          = 0x70, //!< Scanner register value
  RET_RECEIVER_REGISTER_VALUE         = 0x71, //!< Receiver register value
  RET_POSE_VALUE                      = 0x72, //!< Ranging Pose value
  RET_ACTIVE_SENSING_STATE            = 0x73, //!< State of active sensing subsystem
  RET_PASSIVE_SENSING_STATE           = 0x74, //!< State of passive sensing subsystem
  RET_ERPS_SENSING_STATE              = 0x75, //!< State of ERPs sensing subsystem
  RET_RANGING_STATE                   = 0x77, //!< Current sensor range delay
  RET_LASER_STATE                     = 0x78, //!< Current sensor laser state
  RET_MARKER_STATE                    = 0x79, //!< Current sensor marker point sending state
  RET_RECEIVER_REGISTERS_VALUE        = 0x7A, //!< Block of all receiver register values

  CMD_WRITE_SCANNER_REGISTER          = 0xA0, //!< Request to write scanner register values
  CMD_READ_SCANNER_REGISTER           = 0xA1, //!< Request to read scanner register values

  CMD_WRITE_HAWKEYE_REGISTERS         = 0xA2, //!< Request to write hawkeye register values
  RET_READ_HAWKEYE_REGISTERS          = 0xA3, //!< Request to read hawkeye register values

  CMD_SET_NUM_MULTI_ECHOES            = 0xA4,
  CMD_GET_NUM_MULTI_ECHOES            = 0xA5,
  CMD_GET_MODE_MULTI_ECHOES           = 0xA6,

  CMD_REBOOT                          = 0xA7,

  CMD_SET_SKIRT_THRESH_NEAR_HIGH      = 0xA8,
  CMD_SET_SKIRT_THRESH_NEAR_LOW       = 0xA9,
  CMD_SET_SKIRT_THRESH_FAR_HIGH       = 0xAA,
  CMD_SET_SKIRT_THRESH_FAR_LOW        = 0xAB,
  CMD_GET_SKIRT_THRESH_NEAR_HIGH      = 0xAC,
  CMD_GET_SKIRT_THRESH_NEAR_LOW       = 0xAD,
  CMD_GET_SKIRT_THRESH_FAR_HIGH       = 0xAE,
  CMD_GET_SKIRT_THRESH_FAR_LOW        = 0xAF,

  CMD_GET_SHOTLIST_NAME               = 0xB0,
  RET_SHOTLIST_NAME                   = 0xB1,

  RET_DIAG_DATA                       = 0xB2,

  // Hawkeye
  CMD_GET_HAWKEYE_BUFFER              = 0xE0,
  CMD_SET_ARX_PIXEL                   = 0xE1,
  CMD_HAWKEYE_SCANNING_MODE           = 0xE2,
  CMD_SET_RX_FOV                      = 0xE3,

  CMD_GET_NETWORK_CONFIG              = 0xF0, //!< Get system ip, netmask, gateway and cmd port
  CMD_SEND_ZONE_SCAN_PARAMS           = 0xF1,
  CMD_GET_BUILD_INFO_EXTRA            = 0xF2,

  CMD_SET_HFOV                        = 0xF5,
  CMD_GET_HSYNC_PARAMETERS            = 0xF6,

  CMD_GET_TCP_KEEP_ALIVE              = 0xF7,
  CMD_SET_TCP_KEEP_ALIVE              = 0xF8
};


static const uint8_t commandVersionsAE110[][2] = {
    {CMD_GET_BUILD_INFO,                  RET_BUILD_INFO_VERSION},
    {CMD_GET_BUILD_INFO_EXTRA,            RET_DEFAULT_VERSION},
    {CMD_SET_NETWORK_CONFIG,              SET_NETWORK_PARAMS_VERSION},
    {CMD_SET_TIME,                        SET_TIME_VERSION},
    {CMD_SET_NTP_SERVER,                  SET_TIME_SERVER_VERSION},
    {CMD_SET_PTP_SERVER,                  SET_TIME_SERVER_VERSION},
    {CMD_SET_GPTP_SERVER,                 SET_TIME_SERVER_VERSION},
    {CMD_GET_NTP_STATUS,                  SET_TIME_SERVER_VERSION},
    {CMD_GET_PTP_STATUS,                  SET_TIME_SERVER_VERSION},
    {CMD_GET_GPTP_STATUS,                 SET_TIME_SERVER_VERSION},
    {CMD_SET_LASER_ENABLE,                SET_LASER_ENABLE_VERSION},
    {CMD_SET_LASER_CONFIG_FLOAT,          SET_LASER_CONFIG_FLOAT_VERSION},
    {CMD_SET_RANGE_GATE_DELAY,            SET_RANGE_DELAY_VERSION},
    {CMD_SET_POSE,                        SET_POSE_VERSION},
    {CMD_SET_ERPS_BOX_IN_CAM_COORDS,      SET_ROI_VERSION},
    {CMD_START,                           SET_START_VERSION},
    {CMD_STOP,                            SET_DEFAULT_VERSION},
    {CMD_TOGGLE_HAWKEYE,                  ENABLE_HAWKEYE_VERSION},
    {CMD_SET_PASSIVE_SENSING_MODE,        SET_PASSIVE_MODE_VERSION},
    {CMD_SET_HAWKEYE_POINT_MODE,          ENABLE_HAWKEYE_POINT_VERSION},
    {CMD_SET_ADVANCED_RX_SWEEP,           ENABLE_ADVANCED_RX_SWEEP},
    {CMD_SET_ADVANCED_RX_STATIC_MODE,     ENABLE_ADVANCED_RX_STATIC_MODE},
    {CMD_GENERATE_ARX_LUT_V2,             GENERATE_ARX_LUT},
    {CMD_GET_GENERATE_ARX_LUT_V2_STATUS,  GET_GENERATE_ARX_LUT_STATUS},
    {CMD_GET_HAWKEYE_BUFFER,              GET_HAWKEYE_BUFFER},
    {CMD_SET_ARX_PIXEL,                   SET_ARX_PIXEL},
    {CMD_HAWKEYE_SCANNING_MODE,           HAWKEYE_SCANNING_MODE},
    {CMD_RET_MARKER_POINTS,               SET_MARKER_POINTS_VERSION},
    {CMD_SET_POINT_RETURN_MASK,           SET_POINT_RETURN_MASK_VERSION},
    {CMD_SET_INTENSITY_TYPE,              SET_INTENSITY_TYPE_VERSION},
    {CMD_SET_RECEIVER_REGISTER,           SET_RECEIVER_REGISTER_32_VERSION},
    {CMD_GET_RECEIVER_REGISTER,           RET_REGISTER_32_VERSION},
    {CMD_SET_PASSIVE_MODE_PARAMETER,      SET_PASSIVE_PARAM_VERSION},
    {CMD_GET_POSE,                        RET_POSE_VERSION},
    {CMD_GET_ACTIVE_SENSING_STATE,        RET_ACTIVE_STATE_VERSION},
    {CMD_GET_PASSIVE_SENSING_STATE,       RET_PASSIVE_STATE_VERSION},
    {CMD_GET_ERPS_SENSING_STATE,          RET_ROI_STATE_VERSION},
    {CMD_GET_RANGING_STATE,               RET_RANGING_STATE_VERSION},
    {CMD_GET_LASER_STATE,                 RET_LASER_STATE_VERSION},
    {CMD_GET_MARKER_STATE,                RET_POWER_LEVELS_STATE_VERSION},
    {CMD_GET_HW_MODEL,                    RET_HW_MODEL_VERSION},
    {RET_POINT_CLOUD,                     RET_POINTS_VERSION},
    {RET_POINT_CLOUD_DELIM,               RET_POINT_CLOUD_DELIM_VERSION},
    {RET_ADC_BUFFER,                      RET_BUFFERS_VERSION},
    {RET_DEFAULT,                         RET_DEFAULT_VERSION},
    {RET_UNKNOWN,                         RET_UNKNOWN_VERSION},
    {RET_BUILD_INFO,                      RET_BUILD_INFO_VERSION},
    {RET_HW_MODEL,                        RET_HW_MODEL_VERSION},
    {RET_SCANNER_REGISTER_VALUE,          RET_REGISTER_32_VERSION},
    {RET_RECEIVER_REGISTER_VALUE,         RET_REGISTER_32_VERSION},
    {RET_POSE_VALUE,                      RET_POSE_VERSION},
    {RET_ACTIVE_SENSING_STATE,            RET_ACTIVE_STATE_VERSION},
    {RET_PASSIVE_SENSING_STATE,           RET_PASSIVE_STATE_VERSION},
    {RET_ERPS_SENSING_STATE,              RET_ROI_STATE_VERSION},
    {RET_RANGING_STATE,                   RET_RANGING_STATE_VERSION},
    {RET_LASER_STATE,                     RET_LASER_STATE_VERSION},
    {RET_MARKER_STATE,                    RET_POWER_LEVELS_STATE_VERSION},
    {RET_RECEIVER_REGISTERS_VALUE,        RET_RECEIVER_REGISTERS_VERSION},
    {CMD_WRITE_SCANNER_REGISTER,          SET_SCANNER_REGISTER_32_VERSION},
    {CMD_READ_SCANNER_REGISTER,           RET_REGISTER_32_VERSION},
    {CMD_WRITE_HAWKEYE_REGISTERS,         SET_HAWKEYE_REGISTERS},
    {RET_READ_HAWKEYE_REGISTERS,          RET_HAWKEYE_REGISTERS},
    {CMD_SET_NUM_MULTI_ECHOES,            SET_NUM_MULTI_ECHOES},
    {CMD_SET_MODE_MULTI_ECHOES,           SET_MODE_MULTI_ECHOES},
    {CMD_GET_NUM_MULTI_ECHOES,            GET_NUM_MULTI_ECHOES},
    {CMD_GET_MODE_MULTI_ECHOES,           GET_MODE_MULTI_ECHOES},
    {RET_GET_NUM_MULTI_ECHOES,            GET_NUM_MULTI_ECHOES},
    {RET_GET_MODE_MULTI_ECHOES,           GET_MODE_MULTI_ECHOES},
    {CMD_REBOOT,                          SET_DEFAULT_VERSION},
    {CMD_SET_SKIRT_THRESH_NEAR_HIGH,      SET_SKIRT_THRESH_VALUE},
    {CMD_SET_SKIRT_THRESH_NEAR_LOW,       SET_SKIRT_THRESH_VALUE},
    {CMD_SET_SKIRT_THRESH_FAR_HIGH,       SET_SKIRT_THRESH_VALUE},
    {CMD_SET_SKIRT_THRESH_FAR_LOW,        SET_SKIRT_THRESH_VALUE},
    {CMD_GET_SKIRT_THRESH_NEAR_HIGH,      GET_SKIRT_THRESH_VALUE},
    {CMD_GET_SKIRT_THRESH_NEAR_LOW,       GET_SKIRT_THRESH_VALUE},
    {CMD_GET_SKIRT_THRESH_FAR_HIGH,       GET_SKIRT_THRESH_VALUE},
    {CMD_GET_SKIRT_THRESH_FAR_LOW,        GET_SKIRT_THRESH_VALUE},
    {CMD_GET_SHOTLIST_NAME,               GET_SHOTLIST_NAME},
    {RET_SHOTLIST_NAME,                   RET_SHOTLIST_NAME_VERSION},
    {RET_DIAG_DATA,                       RET_DIAG_VERSION},
    {CMD_GET_NETWORK_CONFIG,              SET_NETWORK_PARAMS_VERSION},
    {CMD_SEND_ZONE_SCAN_PARAMS,           SEND_ZONE_SCAN_PARAMS_VERSION},
    {CMD_KILL_SERVICE,                    KILL_SERVICE_VERSION},
    {CMD_SET_RX_FOV,                      SET_DEFAULT_VERSION},
    {CMD_SET_HFOV,                        SET_DEFAULT_VERSION},
    {CMD_GET_HSYNC_PARAMETERS,            GET_HSYNC_PARAMETER_VERSION},
    {CMD_GET_TCP_KEEP_ALIVE,              GET_KEEP_ALIVE_VERSION},
    {CMD_SET_TCP_KEEP_ALIVE,              SET_KEEP_ALIVE_VERSION},
};

inline std::unordered_map<AEyeCommands, uint8_t> BuildCommandVersionMap() {
  std::unordered_map<AEyeCommands, uint8_t> command_version_map;
  constexpr size_t num_commands{sizeof(commandVersionsAE110) / sizeof(commandVersionsAE110[0])};
  for (size_t i{0U}; i < num_commands; i++) {
    AEyeCommands const key{static_cast<AEyeCommands>(commandVersionsAE110[i][0])};
    uint8_t const value{commandVersionsAE110[i][1]};
    command_version_map[key] = value;
  }
  return command_version_map;
}

/**
 * All communications to or from the device will be prefaced with an instance of the aeye_packet_header.
 *
 * All structures are byte aligned (e.g. #pragma pack(1)), and all
 * values are little endian unless explicitly stated otherwise.
 *
 * The header structure begins with a constant 4 byte Magic Word marker "AEYE"
 * (e.g. this assists with alignment/synchronization of the TCP data stream).
 *
 * The tuple of (type, version, size) will uniquely identify the structure of the subsequent packet body.
 *
 * The flags field is reserved for future use.
 *
 * The timestamp (ts_sec, ts_usec) is a unix style timestamp in seconds +
 * microseconds from the epoch.  NOTE:  Timestamps on inbound command messages (to the sensor) are ignored.
 */

/// @typedef AEye Packet Header

#ifdef _MSC_VER
#pragma pack(push,1)
#endif

struct ATTRIBUTE_PACKED PacketHeader {
  char      marker[4] = {'A', 'E', 'Y', 'E'}; ///< Magic Number
  uint16_t  type;
  uint8_t   version; ///< Major revision number of the return types
  uint32_t  bodySize; ///< This is body size
  uint32_t  flags;
  uint32_t  tsSec; ///< Message timestamp seconds
  uint32_t  tsuSec; ///< Message timestamp microseconds
};


/// @typedef AEye Packet Generic Body
typedef struct {
  uint32_t bodySize;
  char body[];
} ATTRIBUTE_PACKED PacketGenericBody;

// Responses

/// @typedef AEye Default Return Packet
// PacketReturnDefault
// type = 0x60, version = 0x01, size = 0x0004
typedef struct {
  uint16_t type;
  uint8_t version;
  int16_t status;
} ATTRIBUTE_PACKED PacketReturnDefault;

/// @typedef AEye Build Information Return Packet
typedef struct {
  int16_t  status;
  uint16_t rxType;
  uint16_t rxMajorRevision;
  uint32_t rxBuildTimestamp;
  uint32_t cameraKmVersion;
  uint32_t cameraFpgaVersion;
  char     buildInfo[]; //!< Current Git branch and commit.
} ATTRIBUTE_PACKED PacketBuildInfoBody;

typedef struct {
  int16_t  status;
  uint8_t  scanPatternFlags;
  uint32_t scanblockId;
  char     macAddress[18]; // including null terminator
} ATTRIBUTE_PACKED PacketBuildInfoExtraBody;

/// @typedef AEye ModelType Return Packet
typedef struct {
  ModelType hwModel; //!< Hardware model type
} ATTRIBUTE_PACKED PacketHWModelInfoBody;

// Range Capture Settings

/// @typedef AEye Active Subregion Bounding zone Command Packet
typedef struct {
  Quadrilateral activeZone;
} ATTRIBUTE_PACKED PacketSetActiveZoneBody;

/// @typedef AEye Laser ROI in camera coordinates
typedef struct {
  Quadrilateral regionOfInterest;
} ATTRIBUTE_PACKED PacketLaserPositionRegionBody;

/// @typedef AEye Laser FOV
typedef struct {
  float laserHFovDegree;
  float laserVFovDegree;
} ATTRIBUTE_PACKED PacketLaserFOVBody;

/// @typedef AEye RangeZeroPointCalibration Packet
typedef struct {
  uint16_t  rngZeroPointCal;
} ATTRIBUTE_PACKED PacketRangeZeroPointCal;

/// @typedef AEye Passive Sensing Subsystem Modality Command Packet
typedef struct {
  uint8_t mode;
} ATTRIBUTE_PACKED PacketSetPassiveModeBody;

/// @typedef AEye Sensing Subsystem Parameter Setting Packet
typedef struct {
  PassiveModeParam param;
  float            value;
} ATTRIBUTE_PACKED PacketSetPassiveParamBody;

typedef struct {
  uint8_t enable;
} ATTRIBUTE_PACKED PacketSetLaserEnable;

/// @typedef AEye Laser Configuration Packet
typedef struct {
  float power;
} ATTRIBUTE_PACKED PacketLaserConfigFloatBody;

/// @typedef AEye Sensor Pose Configuration Packet
typedef struct {
  double  x;
  double  y;
  double  z;
  double  yaw;
  double  pitch;
  double  roll;
} ATTRIBUTE_PACKED PacketSetPoseBody;

/// @typedef AEye Long Buffer Configuration Packet
typedef struct {
  uint8_t useFullADCBufferForAll; // boolean
} ATTRIBUTE_PACKED PacketSetLongBufferForAllBody;

/// @typedef AEye Energy Zones Configuration Packet
typedef struct {
  uint8_t  energyZonesEnabled; // boolean
  uint16_t topDivider;
  uint16_t bottomDivider;
  uint16_t topEnergy;
  uint16_t middleEnergy;
  uint16_t bottomEnergy;
  uint16_t roiEnergy;
} ATTRIBUTE_PACKED PacketEnergyZonesBody;

/// @typedef AEye Sensor Pose Return Packet
typedef struct {
  int16_t status;
  double  x;
  double  y;
  double  z;
  double  yaw;
  double  pitch;
  double  roll;
} ATTRIBUTE_PACKED PacketGetPoseBody;

typedef struct {
  int16_t  status;
  uint16_t xLowerBound;
  uint16_t yLowerBound;
  uint16_t xUpperBound;
  uint16_t yUpperBound;
  uint16_t gridRowNum;
  uint16_t gridColNum;
  uint16_t randomRowNum;
  uint16_t randomColNum;
  uint16_t offsetGridRowNum;
  uint16_t offsetGridColNum;
  float    gridColumnOffset;
  uint16_t movingGridRowNum;
  uint16_t movingGridColNum;
  float    gridRowSpeed;
  float    gridColSpeed;
  uint16_t foveatedGridRowNum;
  uint16_t foveatedGridColNum;
  float    gridFoveationCoefficientRow;
  float    gridFoveationCoefficientCol;
  float    foveatedGridCenterRow;
  float    foveatedGridCenterCol;
  uint16_t foveatedRandomRowNum;
  uint16_t foveatedRandomColNum;
  float    randomFoveationCoefficientRow;
  float    randomFoveationCoefficientCol;
  float    foveatedRandomCenterRow;
  float    foveatedRandomCenterCol;
  int8_t  shotlistIdx;
  uint8_t  passiveSensingMode;
} ATTRIBUTE_PACKED PacketGetPassiveSensingStateBody;

/// @typedef AEye Enhanced-Range Sensing Subsystem State Return Packet
typedef struct {
  int16_t   status;
  uint8_t   ERPsEnabled;
  uint8_t   ERPsNumShots;
  uint8_t   ERPsHorLaserIncr;
  uint8_t   ERPsVertLaserIncr;
  uint16_t  ERPsBoxTopLeftX;
  uint16_t  ERPsBoxTopLeftY;
  uint16_t  ERPsBoxWidth;
  uint16_t  ERPsBoxHeight;
} ATTRIBUTE_PACKED PacketGetERPsStateBody;

/// @typedef AEye Laser State Return Packet
typedef struct {
  int16_t       status;
  uint8_t       laserPower;
  float         laserHFovDegree;
  float         laserVFovDegree;
  Quadrilateral laserZone;
  uint32_t      scannerHRes;
  uint32_t      scannerVRes;
} ATTRIBUTE_PACKED PacketGetLaserStateBodyReturnV2;

/// @typedef AEye Range Delay State Return Packet
typedef struct {
  int16_t  status;
  uint16_t pointReturnMask;
  float    rangeDelay;
} ATTRIBUTE_PACKED PacketGetRangingStateBodyReturn;

/// @typedef AEye Point Return Flags Packet
typedef struct {
  uint16_t pointReturnMask;
} ATTRIBUTE_PACKED PacketSetPointReturnMask;

/// @typedef AEye Intensity Return Type Packet
typedef struct {
  uint8_t value;
} ATTRIBUTE_PACKED PacketSetIntensityType;

/// @typedef AEye Range Delay Configuration Command Packet
typedef struct {
  float rangeGateDelay; //!< Delay in meters before data will be captured
} ATTRIBUTE_PACKED PacketSetRangeGateDelayBody;

/// @typedef AEye LiDAR Service Start Command Packet
typedef struct {
  char      clientIp[16];
  uint16_t  rangePort;
  uint16_t  cameraPort;
} ATTRIBUTE_PACKED PacketStartBody;

/// @typedef AEye Marker Point Sending Enable/Disable Configuration Command Packet
typedef struct {
  uint8_t sendMarkerPoints; // boolean
} ATTRIBUTE_PACKED PacketSendMarkerPoints;

/// @typedef AEye Point Return Body
typedef struct {
  uint64_t  sensorId; ///< [63:48] Unit number, [47:0] MAC address
  uint16_t  frameId;
  uint16_t  seqNum;
  uint16_t  seqTotal;
  uint16_t  pointReturnMask;
  uint8_t   pointData[];
  /// Note: If you want to know number of points per current chunk on client size - use following formula:
  /// pointsPerChunk = (PacketHeader.size - sizeof(PointReturnsBody)) / sum_X ( sizeof(PointReturnX) );
} ATTRIBUTE_PACKED PointReturnsBody;

/// @typedef AEye Point Cloud Return Packet
typedef struct {
  PacketHeader      header;
  PointReturnsBody  body;
} ATTRIBUTE_PACKED PacketPointsReturn;

/// @typedef AEye Point Cloud Delimiter Packet
typedef struct {
  PacketHeader      header;
  uint16_t          frameId;
  uint32_t          numPointsTotalInFrame;
  Pose              sensorPose;
  char              scanPatternName[];
} ATTRIBUTE_PACKED PacketPointCloudDelimiter;

// System Settings
/// @typedef AEye Network Settings Configuration Command Body
typedef struct {
  char      serverIp[16];
  char      netmask[16];
  char      gateway[16];
  uint16_t  commandPort;
} ATTRIBUTE_PACKED PacketNetworkConfigBody;

/// @typedef AEye Network Time Protocol Configuration Command Body
typedef struct {
  uint8_t useNTP; //!< 0 - Disable use NTP server, 1 - Actively use NTP server
  char    serverIp[16]; //!< IP address of the intended NTP Server
} ATTRIBUTE_PACKED PacketSetNtpBody;

/// @typedef AEye Precision Time Protocol Configuration Command Body
typedef struct {
  uint8_t usePTP; //!< 0 - Disable use PTP server, 1 - Actively use PTP server
  char    serverIp[16]; //!< IP address of the intended PTP Server (if valid)
} ATTRIBUTE_PACKED PacketSetPtpBody;

/// @typedef AEye Precision Time Protocol Configuration Command Body
typedef struct {
  uint8_t useGPTP; //!< 0 - Disable use PTP server, 1 - Actively use PTP server
} ATTRIBUTE_PACKED PacketSetGptpBody;

/// @typedef AEye Network Time Protocol Return Parameters Command Body
typedef struct {
  int16_t status; //!< aeye::ReturnStatus
  TimeServerStatus NTPstatus; //!< 0 - synchronized, 1 - not synchronized, 2 - clock state is indeterminate
  float timeCorrectness; //!< difference between clocks server/client or peer/peer
  float timeConstant; //!< 2^(timeConstant) == how often polling server or peer's clock
} ATTRIBUTE_PACKED PacketGetNtpStatus;

/// @typedef AEye Precision Time Protocol Return Parameters Command Body
typedef struct {
  int16_t status; //!< aeye::ReturnStatus
  TimeServerStatus PTPstatus; //!< 0 - synchronized, 1 - not synchronized, 2 - clock state is indeterminate
  char timeStamp[32]; //!< Timestamp recorded according to the PTP daemon
  char state[8]; //!< State of the PTP daemon, i.e. slave, master, initializing...
  char clockId[32]; //!< Unique clockId assigned by the PTP daemon
  float oneWayDelay; //!< the delay of a message one way, according to the state of the PTP daemon
  float offsetFromMaster; //!< the time offset calculated between the PTP daemon and slave
  float slaveToMaster; //!< Intermediate offset value from the delay request
  float masterToSlave; //!< intermediate offset value from the synq request
  float observedDrift; //!< Observer drift between the slave and master
  char lastPacketReceived[8]; //!< last packet received, either donates packet from master (synq request) or slave (delay request)
} ATTRIBUTE_PACKED PacketGetPtpStatus;

typedef struct {
  int16_t status; //!< aeye::ReturnStatus
  TimeServerStatus gPTPstatus; //!< 0 - synchronized, 1 - not synchronized, 2 - clock state is indeterminate
  char stepsRemoved[8]; //!< The number of communication paths to the grandmaster clock
  float offsetFromMaster; //!< The last measured offset of the clock from the master in nanoseconds
  float meanPathDelay; //!< The estimated delay of the synchronization messages sent from the master in nanoseconds
  float masterOffset; //!< The last measured offset of the clock from the master in nanoseconds
  char ingress_time[32]; //!< The "ingress" time stamp of the most recently received sync message
  float cumulativeScaledRateOffset; //!< The calculated scaled rate offset to ensure master-slave sync
  char scaledLastGmPhaserChange[32]; //!< The calculated scaled grandmaster phase change to ensure master-slave sync
  char gmPresent[8]; //!< If true, the gPTP clock is synchronized to a master and the local clock is not the grandmaster
  char gmIdentity[32]; //!< The grandmaster's identity, displayed as an address
  char portIdentity[32]; //!< The slave identity i.e. sensor identity, displayed as an address
  char portState[16]; //!< The active state of the sensor port, INITIALIZING, LISTENING, UNCALIBRATED, or SLAVE
  char logMinDelayReqInterval[32]; //!< The minimum permitted mean time interval between Delay_Req messages
  char peerMeanPathDelay[32]; //!< The mean path delay of messages through the system, calculated between peers
  char logAnnounceInterval[32]; //!< The mean time interval between Announce messages
  char announceReceiptTimeout[32]; //!< The number of missed Announce messages before the last Announce messages expires
  char logSyncInterval[32]; //!< The mean time interval between Sync messages
  char delayMechanism[32]; //!< The delay mechanism, for gPTP this is automaticall set to P2P
  char logMinPdelayReqInterval[32]; //!< The minimum permitted mean time interval between Pdelay_Req messages
  char versionNumber[32]; //!< The current version of the ptp4l application
} ATTRIBUTE_PACKED PacketGetGptpStatus;

/// @typedef AEye Client/Server Time Synchronization Command Body
typedef struct {
  uint32_t tvSec;
  uint32_t tvuSec;
  int32_t tzMinutesWest;
  int32_t tzDstTime;
} ATTRIBUTE_PACKED PacketTimeBody;

/// @typedef Set the number of multi echoes to process
typedef struct {
  uint8_t numEchoes;
} ATTRIBUTE_PACKED PacketSetNumMultiEchoes;

typedef struct {
  MultiEchoMode modeMultiEchoes;
} ATTRIBUTE_PACKED PacketSetModeMultiEchoes;

typedef struct {
  int16_t status;
  uint8_t numEchoes;
} ATTRIBUTE_PACKED PacketGetNumMultiEchoes;

typedef struct {
  int16_t status;
  MultiEchoMode mode;
} ATTRIBUTE_PACKED PacketGetModeMultiEchoes;

typedef struct {
  uint16_t value;
} ATTRIBUTE_PACKED PacketSetSkirtThreshValue;

typedef struct {
  int16_t status;
  uint16_t value;
} ATTRIBUTE_PACKED PacketGetSkirtThreshValue;

// typedefs for packets used to get and return shotlist names
typedef struct {
  uint16_t shotlistIdx;
} ATTRIBUTE_PACKED PacketGetShotlistNameBody;

typedef struct {
  int16_t status;
  uint8_t stringLength;
  char shotlistName[];
} ATTRIBUTE_PACKED PacketReturnShotlistNameBody;

typedef struct {
  PacketHeader header;
  PacketDiagnosticBody body;
} ATTRIBUTE_PACKED PacketDiagnosticData;

#ifdef _MSC_VER
#pragma pack(pop)
#endif


constexpr uint32_t HAWKEYE_BUF_LEN = 512;

enum class BufferType : uint16_t {
  rawHighGain   = 0,
  rawLowGain    = 1,
  procHighGain  = 2,
  procLowGain   = 3,
  aRxSweep      = 4
};

enum class GainChannel : uint8_t {
  high,
  low,
  none,
};

enum class PixelMode : uint32_t {
  _1x1 = 0b000,
  _2x2 = 0b001,
  _3x3_OR_2x3_Gen3 = 0b010,
  _2x6_OR_3x3_Gen3 = 0b011,
  _2x6_Gen3 = 0b100,
};

enum class RxFOV : uint8_t {
  narrow,
  wide,
};

#ifdef _MSC_VER
#pragma pack(push,1)
#endif

/// @typedef AEye FPGA 32-bit Register Value Return Packet
// type = 0x71, version = 0x01
typedef struct {
  uint8_t   type;
  uint8_t   version;
  int16_t   status;
  uint32_t  registerValue; //!< Value of desired register
} ATTRIBUTE_PACKED PacketRegister32Body;

/// @typedef AEye Set FPGA 32-bit Register command body
typedef struct {
  uint32_t address;
  uint32_t value;
} ATTRIBUTE_PACKED PacketSetRegister32Body;

/// @typedef AEye Get FPGA 32-bit Register command body
typedef struct {
  uint32_t address;
} ATTRIBUTE_PACKED PacketGetRegister32Body;

/// @typedef Enable/disable HawkEye Receiver Diagnosis Tool
typedef struct {
  uint8_t  enable;
  uint16_t hawkEyePort;
  char     clientIp[16];
} ATTRIBUTE_PACKED PacketToggleHawkEye;

/// @typedef Enable/disable Advanced Receiver Sweep Tool
typedef struct {
  uint8_t  enable;
  uint16_t hawkEyePort;
  GainChannel gainChannel;
  PixelMode pixelMode;
  uint16_t colSize;
  uint16_t rowSize;
  char     clientIp[16];
} ATTRIBUTE_PACKED PacketToggleARxSweep;

/// @typedef Enable/disable Advanced Receiver Static Mode
typedef struct {
  uint8_t  enable;
  uint16_t hawkEyePort;
  PixelMode pixelMode;
  uint32_t pixelRow;
  uint32_t pixelCol;
  char     clientIp[16];
} ATTRIBUTE_PACKED PacketToggleARxStaticMode;

/// @typedef Control Advanced Receiver LUT Generation
typedef struct {
  RxFOV rxFov;
  PixelMode pixelMode;
  GainChannel gainChannel;
  uint8_t  rxWindowSize;
} ATTRIBUTE_PACKED PacketToggleARxLUT;

/// @typedef Status of Control Advanced Receiver LUT Generation
typedef struct {
  uint8_t isRunning;
  uint8_t calIterations;
  uint8_t startScore;
  uint64_t endScore;
  float ratio;
} ATTRIBUTE_PACKED PacketGetARxLUTV2Status;

typedef struct {
  char clientIp[16];
  uint16_t hawkeyePort;
  uint8_t  enable;
  uint8_t buffType;
  uint32_t bufferCount;
  uint8_t rxCol;
  uint8_t rxRow;
  uint8_t rxPixelMode;
  uint16_t txRow;
  uint16_t txCol;
} ATTRIBUTE_PACKED PacketHawkeyeParams;

/// @typedef Enable/disable HawkEye Debug Point
typedef struct {
  uint8_t  enable;
  uint16_t hawkEyePointRow;
  uint16_t hawkEyePointCol;
} ATTRIBUTE_PACKED PacketHawkEyePoint;

typedef struct {
  uint32_t maxPeak;
  uint32_t rx_row;
  uint32_t rx_col;
  double std_dev;
  uint8_t parity_err;
  uint32_t duration;
} ATTRIBUTE_PACKED SweepInfo;

/// @typedef Raw Signal Buffer Return Packet Body
typedef struct {
  uint64_t   sensorId; ///< [63:48] Unit number, [47:0] MAC address
  uint32_t   grabId;
  BufferType bufferType;
  SweepInfo sweepInfo;
  uint16_t   buffer[HAWKEYE_BUF_LEN];
} ATTRIBUTE_PACKED SignalBufferBody;

/// @typedef Raw Signal Buffer Return Packet
typedef struct {
  PacketHeader     header;
  SignalBufferBody body;
} ATTRIBUTE_PACKED PacketSignalBuffer;

/// @typedef Zone Scan Parameters Packet
typedef struct {
  uint8_t zone_enable_mask;
  AdvancedZoneScanRegion zones[5];
} ATTRIBUTE_PACKED PacketZoneScanParamsBody;

typedef struct {
  RxFOV rx_fov;
} ATTRIBUTE_PACKED PacketSetRxFOVValue;

typedef struct {
  float hfov_percentage;
} ATTRIBUTE_PACKED PacketHFOVConfig;

typedef struct {
    float avg_samples_temp;
    float inst_temp;
    bool  np0_capacitor;
} ATTRIBUTE_PACKED PacketGetHsyncParams;

typedef struct  {
    uint8_t enable;
} ATTRIBUTE_PACKED PacketTCPKeepAlive;

#ifdef _MSC_VER
#pragma pack(pop)
#endif

} // end of namespace aeye

#endif //AEYE_AEYEAPI_H
